#include "Dri_Websocket.h"

#define CONFIG_WEBSOCKET_AUDIO_URI "ws://192.168.137.1:8000/ws/from_esp"
#define CONFIG_WEBSOCKET_VEDIO_URI "ws://192.168.137.1:8000/ws/image"

static const char *TAG = "Websocket";

esp_websocket_client_handle_t client_audio;
esp_websocket_client_handle_t client_vedio;

static void receive_audio(esp_websocket_event_data_t *data)
{
    // 将数据写入ESP8266,播放音频
    Inf_es8311_WriteData((uint8_t *)data->data_ptr, data->data_len);
}

static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
    switch (event_id)
    {
    case WEBSOCKET_EVENT_BEGIN:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_BEGIN");
        break;
    case WEBSOCKET_EVENT_CONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
        break;
    case WEBSOCKET_EVENT_DISCONNECTED:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
        break;
    case WEBSOCKET_EVENT_DATA:
        // ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");
        // ESP_LOGI(TAG, "opcode=%d", data->op_code);
        if (data->op_code == 0x2)
        {
            // Opcode 0x2 indicates binary data
            receive_audio(data);
        }
        else if (data->op_code == 0x08 && data->data_len == 2)
        {
            ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]);
        }
        break;
    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
        break;
    case WEBSOCKET_EVENT_FINISH:
        ESP_LOGI(TAG, "WEBSOCKET_EVENT_FINISH");
        break;
    }
}

RingbufHandle_t ringBuff; // 环形缓冲区

void Dri_Websocket_Init(void)
{
    esp_websocket_client_config_t websocket_cfg = {};
    websocket_cfg.uri = CONFIG_WEBSOCKET_AUDIO_URI;
    /* 初始化 websocket */
    client_audio = esp_websocket_client_init(&websocket_cfg);
    /* 注册事件 */
    esp_websocket_register_events(client_audio,
                                  WEBSOCKET_EVENT_ANY,
                                  websocket_event_handler,
                                  (void *)client_audio);
    /**
     * 创建环形缓冲区
     * 缓冲区大小为4096字节，不进行分割
     * 由于传递音频数据可能出现延迟，卡顿
     * 故采用环形缓冲区进行数据传递
     */
    ringBuff = xRingbufferCreate(4096, RINGBUF_TYPE_NOSPLIT);

    // 由于视频数据只需要发送，故不需要注册事件
    websocket_cfg.uri = CONFIG_WEBSOCKET_VEDIO_URI;
    client_vedio = esp_websocket_client_init(&websocket_cfg);
}

/**
 * @brief 打开websocket
 * @param client websocket client
 */
void Dri_Websocket_Start(esp_websocket_client_handle_t client)
{
    /* 未连接且client不为空，开始连接 */
    if (client && !esp_websocket_client_is_connected(client))
    {
        esp_websocket_client_start(client);
    }
}

/**
 * @brief 关闭websocket
 * @param client websocket client
 */
void Dri_Websocket_Stop(esp_websocket_client_handle_t client)
{
    /* 连接且client不为空，断开连接 */
    if (client && esp_websocket_client_is_connected(client))
    {
        esp_websocket_client_stop(client);
    }
}

/**
 * @brief 发送二进制数据
 * @param client websocket client
 * @param data 二进制数据
 * @param len 数据长度
 */
void Dri_Websocket_send_bin(esp_websocket_client_handle_t client, uint8_t *data, size_t len)
{
    if (client && len > 0 && data && esp_websocket_client_is_connected(client))
    {
        esp_websocket_client_send_bin(client, (char *)data, len, portMAX_DELAY);
    }
}

TaskHandle_t Mic2Ringbuff_task_handle; // 音频采集任务句柄
void Mic2Ringbuff_task(void *args);
TaskHandle_t Ring2Websocket_task_handle; // 音频发送任务句柄
void Ring2Websocket_task(void *args);

volatile uint8_t is_Sending = 0; // 标识发送音频数据启动
volatile uint8_t is_Receive = 0; // 标识接收音频数据启动

TaskHandle_t vedio_task_handle; // 视频发送任务句柄
void vedio_task(void *args);
volatile uint8_t is_SendVedio = 0; // 标识发送视频数据启动

/**
 * @brief 打开audio_websocket
 * @param dir 方向
 */
void Dri_Websocket_audio_open(uint8_t dir)
{
    Dri_Websocket_Start(client_audio);
    if (dir == DIR_ESP2CLIENT) // 打开esp到client的音频发送
    {
        is_Sending = 1;
    }
    if (dir == DIR_CLIENT2ESP) // 打开client到esp的音频接收
    {
        is_Receive = 1;
    }
    if (dir == DIR_ESP2CLIENT && ringBuff != NULL)
    {
        if (Mic2Ringbuff_task_handle == NULL)
        {
            xTaskCreate(Mic2Ringbuff_task,
                        "Mic2Ringbuff_task",
                        8192,
                        NULL, 15, &Mic2Ringbuff_task_handle);
        }
        if (Ring2Websocket_task_handle == NULL)
        {
            xTaskCreate(Ring2Websocket_task,
                        "Ring2Websocket_task",
                        8192,
                        NULL, 15, &Ring2Websocket_task_handle);
        }
    }
}

/**
 * @brief 关闭audio_websocket
 * @param dir 方向
 */
void Dri_Websocket_audio_close(uint8_t dir)
{
    if (dir == DIR_ESP2CLIENT)
    {
        is_Sending = 0;
    }
    if (dir == DIR_CLIENT2ESP)
    {
        is_Receive = 0;
    }
    if (is_Receive == 0 && is_Sending == 0)
    {
        Dri_Websocket_Stop(client_audio);
    }
}

void Dri_Websocket_vedio_open(void)
{
    Dri_Websocket_Start(client_vedio);
    if (vedio_task_handle==NULL)
    {
        is_SendVedio = 1;
        xTaskCreate(vedio_task,
                    "vedio_task",
                    8192,
                    NULL, 15, &vedio_task_handle);
    }
    
}

void Dri_Websocket_vedio_close(void)
{
    is_SendVedio = 0;
    Dri_Websocket_Stop(client_vedio);
}

void Mic2Ringbuff_task(void *args)
{
    /**
     * 采集音频数据
     * 每次采集1024-8个字节，
     * 因为环形数组中数据包含头信息一个uint32_t的header，
     * 所以每次采集的音频数据长度为 1024 - 8
     */
    MY_LOGE("创建Mic2Ringbuff_task");
    uint8_t data[1024 - 8] = {0};
    size_t len = 0;
    while (1)
    {
        Inf_es8311_ReadData(data, sizeof(data));
        len = sizeof(data);
        if (len > 0)
        {
            // 将数据写入环形缓冲区
            xRingbufferSend(ringBuff, data, len, 1000 / portTICK_PERIOD_MS);
        }
        if (is_Sending == 0)
        {
            Mic2Ringbuff_task_handle = NULL;
            MY_LOGE("删除Mic2Ringbuff_task");
            vTaskDelete(NULL);
        }
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

void Ring2Websocket_task(void *args)
{
    MY_LOGE("创建Ring2Websocket_task");
    size_t size = 0;
    while (1)
    {
        size = 0;
        // 从环形缓冲区中读取数据
        uint8_t *data = (uint8_t *)xRingbufferReceive(ringBuff, &size, 1000 / portTICK_PERIOD_MS);
        if (data && size > 0)
        {
            Dri_Websocket_send_bin(client_audio, data, size);
            // 释放环形缓冲区中读取的数据
            vRingbufferReturnItem(ringBuff, data);
        }
        if (is_Sending == 0)
        {
            MY_LOGE("删除Ring2Websocket_task");
            Ring2Websocket_task_handle = NULL;
            vTaskDelete(NULL);
        }
        // 增加任务延迟，确保发送任务有足够的时间发送数据
        vTaskDelay(5 / portTICK_PERIOD_MS); // 修改: 增加任务延迟
    }
}

void vedio_task(void *args)
{   
    MY_LOGE("创建vedio_task");
    uint8_t *data = NULL;
    size_t len = 0;
    while (1)
    {
        data = NULL;
        len = 0;
        Inf_ov2640_GetPic(&data, &len);
        Dri_Websocket_send_bin(client_vedio, data, len);
        Inf_ov2640_ReturnPic();
        if (is_SendVedio == 0)
        {
            MY_LOGE("删除vedio_task");
            vedio_task_handle = NULL;
            vTaskDelete(NULL);
        }
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}
